﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cosoware.Web.Documents
{
    public abstract class RepositoryProvider
    {
        /// <summary>
        /// Gets the document by identifier.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        internal Document GetDocument(Guid id)
        {
            lock(this)
            {
                return ReadDocumentInternal(id);   
            }
        }

        /// <summary>
        /// Saves the new or existed document.
        /// </summary>
        /// <param name="document">The document.</param>
        internal void SaveDocument(Document document)
        {
            lock (this)
            {
                if (CountDocumentsInternal(d => d.ID == document.ID) == 0)
                    CreateDocumentInternal(document);
                else
                    UpdateDocumentInternal(document);
            }
        }

        /// <summary>
        /// Remove the document.
        /// </summary>
        /// <param name="id">The document identifier.</param>
        internal void RemoveDocument(Guid id)
        {
            lock (this)
            {
                DeleteDocumentInternal(id);
            }
        }

        /// <summary>
        /// Finds the documents.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        /// <returns>The documents.</returns>
        internal IEnumerable<Document> FindDocuments(Func<Document, bool> predicate)
        {
            lock (this)
            {
                return ListDocumentsInternal(predicate);
            }
        }

        /// <summary>
        /// Counts the documents.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        /// <returns>The count of documents.</returns>
        internal int CountDocuments(Func<Document, bool> predicate)
        {
            lock (this)
            {
                return CountDocumentsInternal(predicate);
            }
        }

        /// <summary>
        /// Reads the document.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        protected abstract Document ReadDocumentInternal(Guid id);

        /// <summary>
        /// Creates the document.
        /// </summary>
        /// <param name="document">The document.</param>
        protected abstract void CreateDocumentInternal(Document document);

        /// <summary>
        /// Updates the document.
        /// </summary>
        /// <param name="document">The document.</param>
        protected abstract void UpdateDocumentInternal(Document document);

        /// <summary>
        /// Deletes the document.
        /// </summary>
        /// <param name="id">The document identifier.</param>
        protected abstract void DeleteDocumentInternal(Guid id);

        /// <summary>
        /// Lists the documents that maches the predicate.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        /// <returns>The enumeration of documents.</returns>
        protected abstract IEnumerable<Document> ListDocumentsInternal(Func<Document, bool> predicate);

        /// <summary>
        /// Counts the documents that maches the predicate.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        /// <returns>The count of documents.</returns>
        protected abstract int CountDocumentsInternal(Func<Document, bool> predicate);
    }
}
